using UnityEngine;
using System.Collections;


public class TreeNode  {
    
    public int x;
    public int y;
    public int height;
    public int width;
    public TreeNode leftChild;
    public TreeNode rightChild;
    private TreeNode parent;
    public static int ratio;
    private int minSize = 50;
    public int roomX = 0;
    public int roomY = 0;
    public int roomWidth;
    public int roomHeight;
    public bool horizontal;
    public static int counter = 1;
    public static int minRoomSize;
    public static int maxRoomSize;
    
    
    /* The constructor for tree nodes */
    public TreeNode(int pX, int pY, int pWidth, int pHeight)
    {
        this.x = pX;
        this.y = pY;
        this.height = pHeight;
        this.width = pWidth;
        leftChild = null;
        rightChild = null;
        parent = null;
    }
    /*The logic for calling and splitting the squares.This randomizes 
     *to be horizontal or vertical and then stores the value into a list*/
    public bool split()
    {
        if( leftChild != null)
        {
            leftChild.split();
            rightChild.split();
            return true;
        }
        else
        {
            horizontal = TorF();//need to make a random function for this (done)
            int max = (horizontal ? height : width) - minSize;
            if(max < minSize)
            {
                minSize /= 2;
                max += minSize;
            }
            int split = RndInt(minSize, max);//random function here as well(done)
        
            TreeNode []listA;
            if(horizontal)
            {
                leftChild = new TreeNode(x, y, width, split);
                rightChild = new TreeNode(x, y + split, width, height - split);
                Buttons.list[counter] = leftChild;
                counter++;
                Buttons.list[counter] = rightChild;
                counter++;
                listA = Buttons.list;
                Buttons.list = new TreeNode[listA.Length + 2];
                for(int i = 0; i < listA.Length; i++)
                {
                    Buttons.list[i] = listA[i];
                }
            }
            else
            {
                leftChild = new TreeNode(x, y, split, height);
                rightChild = new TreeNode(x + split, y, width - split, height);
                Buttons.list[counter]=leftChild;
                counter++;
                Buttons.list[counter] = rightChild;
                counter++;
                listA = Buttons.list;
                Buttons.list = new TreeNode[listA.Length + 2];
                for(int i = 0; i < listA.Length; i++)
                {
                    Buttons.list[i] = listA[i];
                }
            }
        
            rightChild.parent = this;
            leftChild.parent = this;
        
            return true;
        }
    }
    /*This generates the room and does it through recursion*/
    public void generateRooms()//need to finish(done)
    {
        if(leftChild != null)
        {
            leftChild.generateRooms();
            rightChild.generateRooms();
        }
        else
        {
            if(parent != null)
            {
                if(parent.horizontal)//will ensure an overlap between sister node rooms
                {
                    int min = this.width/2 + 1;
                    if(min < Buttons.minRoomSize)
                    {
                        min = Buttons.minRoomSize;
                    }
                    roomX = Random.Range(this.x + 1, this.x + this.width - 1 - min);
                    roomY = RndInt(this.y + 1, this.y + this.height - (Buttons.minRoomSize + 1));
                    roomWidth = Random.Range(min, (int)(((this.x + this.width) *(Buttons.maxRoomSize/100.0))- 1) - this.roomX);
                    roomHeight = Random.Range(Buttons.minRoomSize, (int)((this.height - (roomY - y))*(Buttons.maxRoomSize/100.0)) - 1 );
                }
                else
                {
                    int min = this.height/2 + 1;
                    if(min < Buttons.minRoomSize)
                    {
                        min = Buttons.minRoomSize;
                    }
                    roomX = Random.Range(this.x + 1, this.x + this.width - (Buttons.minRoomSize + 1));
                    roomY = Random.Range(this.y + 1, this.y + this.height - 1 - min);
                    roomWidth = Random.Range(Buttons.minRoomSize, (int)((this.width - (roomX - x))*(Buttons.maxRoomSize/100.0)) - 1);
                    roomHeight = Random.Range(min, (int)(((this.y + this.height) * (Buttons.maxRoomSize/100.0)) - 1) - this.roomY);
                }
            }
            else
            {
                int min = this.width/2 + 1;
                roomX = Random.Range(x + 1, width - 1 - min);
                roomY = Random.Range(y + 1, height - 1 - min);
                roomWidth = Random.Range(min, (x + width - 1) - roomX);
                roomHeight = Random.Range(min, (y + height - 1) - roomY);
            }
        }
    }
    
    public void generateCorridors(int index)
    {
        if(index == counter) index = index/2 - 1;
        
        if(Buttons.list[index] != null)
        {
            int leftMin, rightMin, leftMax, rightMax;
            int minBound, maxBound;
        
            if(Buttons.list[index].horizontal)
            {
                if(Buttons.list[index].rightChild.rightChild == null)
                {
                    leftMin = Buttons.list[index].leftChild.roomX;
                    rightMin = Buttons.list[index].rightChild.roomX;
                    leftMax = (Buttons.list[index].leftChild.roomX + Buttons.list[index].leftChild.roomWidth);
                    rightMax = (Buttons.list[index].rightChild.roomX + Buttons.list[index].rightChild.roomWidth);
            
                    minBound = (leftMin < rightMin ? rightMin : leftMin);
                    maxBound = (leftMax > rightMax ? rightMax - 2 : leftMax - 2);
            
                    Buttons.list[index].roomX = RndInt(minBound, maxBound);
                    Buttons.list[index].roomY = Buttons.list[index].leftChild.roomY + Buttons.list[index].leftChild.roomHeight;
                    Buttons.list[index].roomWidth = 2;
                    Buttons.list[index].roomHeight = Buttons.list[index].rightChild.roomY - Buttons.list[index].roomY;
                }
                else
                {
                    leftMin = Buttons.list[index].leftChild.GetMinHor();
                    rightMin = Buttons.list[index].rightChild.GetMinHor();
                    leftMax = Buttons.list[index].leftChild.GetMaxHor();
                    rightMax = Buttons.list[index].rightChild.GetMaxHor();
            
                    minBound = (leftMin < rightMin ? rightMin : leftMin);
                    maxBound = (leftMax > rightMax ? rightMax - 2 : leftMax - 2);
            
                    Buttons.list[index].roomX = RndInt(minBound, maxBound);
                    Buttons.list[index].roomY = Buttons.list[index].SearchLeftHor(Buttons.list[index].roomX, index);
                    Buttons.list[index].roomWidth = 2;
                    //Buttons.list[index].roomHeight = 20;
                    Buttons.list[index].roomHeight = Buttons.list[index].SearchRightHor(Buttons.list[index].roomX, index) - Buttons.list[index].roomY;
                }
            }
            else
            {
                if(Buttons.list[index].rightChild.rightChild == null)
                {
                    leftMin = Buttons.list[index].leftChild.roomY;
                    rightMin = Buttons.list[index].rightChild.roomY;
                    leftMax = (Buttons.list[index].leftChild.roomY + Buttons.list[index].leftChild.roomHeight);
                    rightMax = (Buttons.list[index].rightChild.roomY + Buttons.list[index].rightChild.roomHeight);
            
                    minBound = (leftMin < rightMin ? rightMin : leftMin);
                    maxBound = (leftMax > rightMax ? rightMax -2 : leftMax -2);
            
                    Buttons.list[index].roomY = RndInt(minBound, maxBound);
                    Buttons.list[index].roomX = Buttons.list[index].leftChild.roomX + Buttons.list[index].leftChild.roomWidth;
                    Buttons.list[index].roomHeight = 2;
                    Buttons.list[index].roomWidth = Buttons.list[index].rightChild.roomX - Buttons.list[index].roomX;
                }
                else
                {
                    leftMin = Buttons.list[index].leftChild.GetMinVert();
                    rightMin = Buttons.list[index].rightChild.GetMinVert();
                    leftMax = Buttons.list[index].leftChild.GetMaxVert();
                    rightMax = Buttons.list[index].rightChild.GetMaxVert();
            
                    minBound = (leftMin < rightMin ? rightMin : leftMin);
                    maxBound = (leftMax > rightMax ? rightMax -2 : leftMax -2);
            
                    Buttons.list[index].roomY = RndInt(minBound, maxBound);
                    Buttons.list[index].roomX = Buttons.list[index].SearchLeftVert(Buttons.list[index].roomY, index);
                    Buttons.list[index].roomHeight = 2;
                    Buttons.list[index].roomWidth = Buttons.list[index].SearchRightVert(Buttons.list[index].roomY, index) - Buttons.list[index].roomX;
                }
            }
            
            generateCorridors(index - 1);
        }
        
        
    }
  
    private bool TorF()
    {
        int rnd = Random.Range(0, 1000);
        if( rnd > 500 && (float)height/(float)width > 1.0/(float)ratio)
        {
            return true;
        }
        else if((float)width/(float)height > 1.0/(float)ratio)
        {
            return false;
        }
        else
        {
            return true;
        }
    }
    
    private int RndInt(int min, int max)
    {
        return Random.Range(min, max);
    }
    
        private int GetMinHor()
    {
        TreeNode cur = this;
        int min = Buttons.list[0].x + Buttons.list[0].width;
        while(cur != null)
        {
            
            if(min > cur.roomX)
            {
                min = cur.roomX;
            }
            cur = cur.leftChild;
        }
        return min;
    }
    
    private int GetMaxHor()
    {
        TreeNode cur = this;
        int max = Buttons.list[0].x;
        while(cur != null)
        {
            
            if(max < cur.roomX + cur.roomWidth)
            {
                max = cur.roomX + cur.roomWidth;
            }
            cur = cur.rightChild;
        }
        return max;
    }
    
    private int GetMinVert()
    {
        TreeNode cur = this;
        int min = Buttons.list[0].y + Buttons.list[0].height;
        while(cur != null)
        {
            
            if(min > cur.roomY)
            {
                min = cur.roomY;
            }
            cur = cur.leftChild;
        }
        return min;
    }
    
    private int GetMaxVert()
    {
        TreeNode cur = this;
        int max = Buttons.list[0].y;
        while(cur != null)
        {
            
            if(max < cur.roomY + cur.roomHeight)
            {
                max = cur.roomY + cur.roomHeight;
            }
            cur = cur.rightChild;
        }
        return max;
    }
    
    private int SearchLeftHor(int corX, int pIndex)
    {
        int yNeed = Buttons.list[0].y ;
        int repeat = 1;
        if(this.leftChild.roomX <= corX && corX < this.leftChild.roomX + this.leftChild.roomWidth)
            {
                if(yNeed <= this.leftChild.roomY + this.leftChild.roomHeight)
                {
                    yNeed = this.leftChild.roomY + this.leftChild.roomHeight;
                }
            }
        for(int i = (pIndex * 2 + 1) * 2 + 1; i < counter; i = i * 2 +1)
        {
            repeat *= 2;
            for(int j = 0; j < repeat; j++)
            {
                if(Buttons.list[i + j].roomX <= corX && corX < Buttons.list[i + j].roomX + Buttons.list[i + j].roomWidth)
                {
                    if(yNeed <= Buttons.list[i + j].roomY + Buttons.list[i + j].roomHeight)
                    {
                        yNeed = Buttons.list[i + j].roomY + Buttons.list[i + j].roomHeight;
                    }
                }
            }
        }
        
        return yNeed;
    }
    
    private int SearchRightHor(int corX, int pIndex)
    {
        int yNeed = Buttons.list[0].y + Buttons.list[0].height;
        int repeat = 1;
        if(this.rightChild.roomX <= corX && corX < this.rightChild.roomX + this.rightChild.roomWidth)
        {
            if(yNeed >= this.rightChild.roomY + this.rightChild.roomHeight)
            {
                yNeed = this.rightChild.roomY + this.rightChild.roomHeight;
            }
        }
        for(int i = (pIndex * 2 + 2) * 2 + 1; i < counter; i = i * 2 +1)
        {
            repeat *= 2;
            for(int j = 0; j < repeat; j++)
            {
                if(Buttons.list[i + j].roomX <= corX && corX < Buttons.list[i + j].roomX + Buttons.list[i + j].roomWidth)
                {
                    if(yNeed >= Buttons.list[i + j].roomY)
                    {
                        yNeed = Buttons.list[i + j].roomY;
                    }
                }
            }
        }
        
        return yNeed;
    }
    
    private int SearchLeftVert(int corY, int pIndex)
    {
        int xNeed = Buttons.list[0].x ;
        int repeat = 1;
        if(this.leftChild.roomY <= corY && corY < this.leftChild.roomY + this.leftChild.roomHeight)
            {
                if(xNeed <= this.leftChild.roomX + this.leftChild.roomWidth)
                {
                    xNeed = this.leftChild.roomX + this.leftChild.roomWidth;
                }
            }
        for(int i = (pIndex * 2 + 1) * 2 + 1; i < counter; i = i * 2 +1)
        {
            repeat *= 2;
            for(int j = 0; j < repeat; j++)
            {
                if(Buttons.list[i + j].roomY <= corY && corY < Buttons.list[i + j].roomY + Buttons.list[i + j].roomHeight)
                {
                    if(xNeed <= Buttons.list[i + j].roomX + Buttons.list[i + j].roomWidth)
                    {
                        xNeed = Buttons.list[i + j].roomX + Buttons.list[i + j].roomWidth;
                    }
                }
            }
        }
        
        return xNeed;
    }
    
    private int SearchRightVert(int corY, int pIndex)
    {
        int xNeed = Buttons.list[0].x + Buttons.list[0].width;
        int repeat = 1;
        if(this.rightChild.roomY <= corY && corY < this.rightChild.roomY + this.rightChild.roomHeight)
        {
            if(xNeed >= this.rightChild.roomX + this.rightChild.roomWidth)
            {
                xNeed = this.rightChild.roomX + this.rightChild.roomWidth;
            }
        }
        for(int i = (pIndex * 2 + 2) * 2 + 1; i < counter; i = i * 2 +1)
        {
            repeat *= 2;
            for(int j = 0; j < repeat; j++)
            {
                if(Buttons.list[i + j].roomY <= corY && corY < Buttons.list[i + j].roomY + Buttons.list[i + j].roomHeight)
                {
                    if(xNeed >= Buttons.list[i + j].roomX)
                    {
                        xNeed = Buttons.list[i + j].roomX;
                    }
                }
            }
        }
        
        return xNeed;
    }
}